/*
 * AbstractButtonDelegate.cpp  0.4.0 / Dec 04, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "AbstractButtonDelegate.h"

#include "QAbstractButtonAdapter.h"
#include "QApplicationDelegate.h"
#include "SwingDelegate.h"

// AbstractButtonDelegate :: Protected Constructors. ---------------------------

/*!
 * \brief Constructs new AbstractButtonDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the AbstractButton java object
 * \param button the QAbstractButton object
 */
AbstractButtonDelegate::AbstractButtonDelegate(JNIEnv *env, jobject obj,
                                               QAbstractButton *button)
  : ComponentDelegate(env, obj, button), m_modifiers(Qt::NoModifier),
    m_iconType(QIconAdapter::DefaultIcon)
{
  connectDirect(qAbstractButton(), SIGNAL(pressed()), SLOT(pressedSlot()));
  connectDirect(qAbstractButton(), SIGNAL(released()), SLOT(releasedSlot()));
  connectDirect(qAbstractButton(), SIGNAL(clicked()), SLOT(clickedSlot()));
}

/*!
 * \brief Constructs new AbstractButtonDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the AbstractButton java object
 */
AbstractButtonDelegate::AbstractButtonDelegate(JNIEnv *env, jobject obj)
  : ComponentDelegate(env, obj, new QAbstractButtonAdapter()),
    m_modifiers(Qt::NoModifier), m_iconType(QIconAdapter::DefaultIcon)
{
  connectDirect(qAbstractButton(), SIGNAL(pressed()), SLOT(pressedSlot()));
  connectDirect(qAbstractButton(), SIGNAL(released()), SLOT(releasedSlot()));
  connectDirect(qAbstractButton(), SIGNAL(clicked()), SLOT(clickedSlot()));
}

// AbstractButtonDelegate :: Native Calls. -------------------------------------

/*!
 * \brief Pressed/unpressed the button.
 *
 * \param env the JNIEnv pointer 
 * \param pressed \c true if pressed
 */
void AbstractButtonDelegate::setPressed(JNIEnv *env, jboolean pressed)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setPressed, SWING_ENV_ARG, JBOOLEAN_ARG(pressed))
  qAbstractButton()->setDown(pressed);
}

/*!
 * \brief Sets button text.
 *
 * \param env the JNIEnv pointer 
 * \param text the text
 */
void AbstractButtonDelegate::setText(JNIEnv *env, jstring text)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setText, SWING_ENV_ARG, JSTRING_ARG(text))
  qAbstractButton()->setText(QStringAdapter(env, text));
}

/*!
 * \brief Sets the icon set.
 *
 * \param env the JNIEnv pointer 
 * \param iconSet the icon set
 */
void AbstractButtonDelegate::setIcon(JNIEnv *env, jobject iconSet)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setIcon, SWING_ENV_ARG, JOBJECT_ARG(iconSet))
  if (iconSet) {
    qAbstractButton()->setIcon(QIconAdapter(env, iconSet, &m_iconType));
    qAbstractButton()->setMouseTracking(true);
  } else {
    qAbstractButton()->setIcon(QIcon());
  }
}

/*!
 * \brief Sets icon size.
 *
 * \param env the JNIEnv pointer 
 * \param width the icon width 
 * \param height the icon height 
 */
void AbstractButtonDelegate::setIconSize(JNIEnv *env, jint width, jint height)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setIconSize, SWING_ENV_ARG, JINT_ARG(width), JINT_ARG(height))
  qAbstractButton()->setIconSize(QSize(width, height));
}

// AbstractButtonDelegate :: Static Native Calls. ------------------------------

/*!
 * \brief Initializes AbstractButtonDelegate class.
 *
 * \param env the JNIEnv pointer
 * \param cls the AbstractButton java class
 *
 * \exception FatalError if failed
 */
void AbstractButtonDelegate::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT (!sm_buttonPressedMID);
  if (!INIT_UMID(buttonPressed, cls, "()Z") ||
      !INIT_UMID(buttonReleased, cls, "()Z") ||
      !INIT_UMID(buttonClicked, cls, "(I)V")) {
    FATAL_LOGGED_ERROR("AbstractButtonDelegate initialization failed");
  }
}

/*!
 * \brief Returns new instance of the delegate object.
 *
 * \param env the JNIEnv pointer 
 * \param obj the AbstractButton java object
 * 
 * \return new instance of the delegate object
 */
jlong AbstractButtonDelegate::newInstance(JNIEnv *env, jobject obj)
{
  if (JNISwingWrapper::isSwingThread(env)) {
    return reinterpret_cast<jlong>(new AbstractButtonDelegate(env, obj));
  }
  return SwingUtilitiesDelegate::invokeLongAndWait(env, obj, createMID());
}

// AbstractButtonDelegate :: Native Callbacks. ---------------------------------

/*!
 * \brief Calls buttonPressed method of the AbstractButton java object.
 *
 * \return \c true if the button is pressed
 */
jboolean AbstractButtonDelegate::buttonPressed()
{
  jboolean result;
  jniObject()->callBooleanMethod(result, sm_buttonPressedMID);
  return result;
}

/*!
 * \brief Calls buttonReleased method of the AbstractButton java object.
 *
 * \return \c true if the button is released
 */
jboolean AbstractButtonDelegate::buttonReleased()
{
  jboolean result;
  jniObject()->callBooleanMethod(result, sm_buttonReleasedMID);
  return result;
}

/*!
 * \brief Calls buttonClicked method of the AbstractButton java object.
 */
void AbstractButtonDelegate::buttonClicked(jint modifiers)
{
  jniObject()->callVoidMethod(sm_buttonClickedMID, modifiers);
}

// AbstractButtonDelegate :: Overridden Member Functions. ----------------------

/*!
 * \inheritDoc
 */
jobject AbstractButtonDelegate::getBackground(JNIEnv *env, jclass colorClass)
{
  return QColorAdapter::toJColor(env, colorClass,
                          qAbstractButton()->palette().color(QPalette::Button));
}

/*!
 * \inheritDoc
 */
void AbstractButtonDelegate::setBackground(JNIEnv *env, jint argb)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setBackground, SWING_ENV_ARG, JINT_ARG(argb))
  QColorAdapter color(argb);
  QPalette palette(qAbstractButton()->palette());
  if (color.isValid()) {
    palette.setColor(QPalette::Button, color);
    palette.setColor(QPalette::Window, color);
  } else {
    palette.setColor(QPalette::Button,
                     QApplication::palette().color(QPalette::Button));
    palette.setColor(QPalette::Window,
                     QApplication::palette().color(QPalette::Window));
  }
  qAbstractButton()->setPalette(palette);
}

/*!
 * \inheritDoc
 */
void AbstractButtonDelegate::setNullBackground(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setNullBackground, SWING_ENV_ARG)
  QPalette palette(qWidget()->palette());
  palette.setColor(QPalette::Button,
                   QApplication::palette().color(QPalette::Button));
  palette.setColor(QPalette::Window,
                   QApplication::palette().color(QPalette::Window));
  qAbstractButton()->setPalette(palette);
}

/*!
 * \inheritDoc
 */
jobject AbstractButtonDelegate::getForeground(JNIEnv *env, jclass colorClass)
{
  return QColorAdapter::toJColor(env, colorClass,
                      qAbstractButton()->palette().color(QPalette::ButtonText));
}

/*!
 * \inheritDoc
 */
void AbstractButtonDelegate::setForeground(JNIEnv *env, jint argb)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setForeground, SWING_ENV_ARG, JINT_ARG(argb))
  QColorAdapter color(argb);
  QPalette palette(qAbstractButton()->palette());
  if (color.isValid()) {
    palette.setColor(QPalette::ButtonText, color);
    palette.setColor(QPalette::WindowText, color);
  } else {
    palette.setColor(QPalette::ButtonText,
                     QApplication::palette().color(QPalette::ButtonText));
    palette.setColor(QPalette::WindowText,
                     QApplication::palette().color(QPalette::WindowText));
  }
  qAbstractButton()->setPalette(palette);
}

/*!
 * \inheritDoc
 */
void AbstractButtonDelegate::setNullForeground(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setNullForeground, SWING_ENV_ARG)
  QPalette palette(qWidget()->palette());
  palette.setColor(QPalette::ButtonText,
                   QApplication::palette().color(QPalette::ButtonText));
  palette.setColor(QPalette::WindowText,
                   QApplication::palette().color(QPalette::WindowText));
  qAbstractButton()->setPalette(palette);
}

// AbstractButtonDelegate :: Overridden Member Functions. ----------------------

/*!
 * \inheritDoc
 */
bool AbstractButtonDelegate::filterKeyPressedEvent(QObject *obj, QKeyEvent *e)
{
  m_modifiers |= e->modifiers();
  return ComponentDelegate::filterKeyPressedEvent(obj, e);
}

/*!
 * \inheritDoc
 */
bool AbstractButtonDelegate::filterKeyReleasedEvent(QObject *obj, QKeyEvent *e)
{
  m_modifiers &= ~SwingDelegate::toKeyboardModifiers(e->key());
  return ComponentDelegate::filterKeyPressedEvent(obj, e);
}

/*!
 * \inheritDoc
 */
bool AbstractButtonDelegate::filterMouseEnterEvent(QObject *obj, QMouseEvent *e)
{
  if (qAbstractButton()->isChecked()) {
    setIconType(QIconAdapter::RolloverSelectedIcon);
  } else {
    setIconType(QIconAdapter::RolloverIcon);
  }
  qAbstractButton()->update();
  return ComponentDelegate::filterMouseEnterEvent(obj, e);
}

/*!
 * \inheritDoc
 */
bool AbstractButtonDelegate::filterMouseLeaveEvent(QObject *obj, QMouseEvent *e)
{
  if (qAbstractButton()->isChecked()) {
    setIconType(QIconAdapter::SelectedIcon);
  } else {
    setIconType(QIconAdapter::DefaultIcon);
  }
  qAbstractButton()->update();
  return ComponentDelegate::filterMouseLeaveEvent(obj, e);
}

// AbstractButtonDelegate :: Protected Member Functions. -----------------------

/*!
 * \brief Pressed slot.
 */
void AbstractButtonDelegate::pressedSlot()
{
  if (!buttonPressed()) {
    setEventFilterEnabled(false);
    if (qAbstractButton()->isCheckable()) {
      qAbstractButton()->setChecked(!qAbstractButton()->isChecked());
    } else {
      qAbstractButton()->setDown(false);
    }
    setEventFilterEnabled(true);
  } else {
    setIconType(QIconAdapter::PressedIcon);
    qAbstractButton()->update();
  }
}

/*!
 * \brief Released slot.
 */
void AbstractButtonDelegate::releasedSlot()
{
  if (!buttonReleased()) {
    setEventFilterEnabled(false);
    qAbstractButton()->setDown(true);
    setEventFilterEnabled(true);
  } else {
    if (qAbstractButton()->isChecked()) {
      if (qAbstractButton()->underMouse()) {
        setIconType(QIconAdapter::RolloverSelectedIcon);
      } else {
        setIconType(QIconAdapter::SelectedIcon);
      }
    } else {
      if (qAbstractButton()->underMouse()) {
        setIconType(QIconAdapter::RolloverIcon);
      } else {
        setIconType(QIconAdapter::DefaultIcon);
      }
    }
    qAbstractButton()->update();
  }
}

/*!
 * \brief \c clicked slot.
 */
void AbstractButtonDelegate::clickedSlot()
{
  buttonClicked(SwingDelegate::toSwingModifiers(m_modifiers));
}

// AbstractButtonDelegate :: Private Static Data Members. ----------------------

jmethodID AbstractButtonDelegate::sm_buttonPressedMID = 0;
jmethodID AbstractButtonDelegate::sm_buttonReleasedMID = 0;
jmethodID AbstractButtonDelegate::sm_buttonClickedMID = 0;
